home *** CD-ROM | disk | FTP | other *** search
- #include <exec/types.h>
-
- #define CUE 0
- #define BLK 5
-
- #define BASE 200 /* V.important constant. Used in ALL physical calcs. */
- #define BASESP 1000
- #define BASEII 4 /* For root calcs which need plenty of precision */
-
- #define TABLELENGTH (272 * BASE) /* 272 is actual length in pixels */
- #define TABLEWIDTH ((TABLELENGTH * 5 / 8)-BASE)
-
- #define X1CORNER 24
- #define Y1CORNER 62
- #define X2CORNER (X1CORNER + TABLELENGTH / BASE)
- #define Y2CORNER (Y1CORNER + TABLEWIDTH / BASE)
-
- #define BALLRADIUS (7 * BASE) /* 7 pixels */
- #define BALLDIAMETER (BALLRADIUS * 2)
- #define SCRNBALLDIAMETER (BALLDIAMETER / BASE)
- #define SEMICIRCRAD (TABLEWIDTH/6)
- #define PLACEPACK (TABLELENGTH * 5 / 8)
- #define PACKHORIZSEP (BALLDIAMETER - 2*BASE)
- #define POCKET (BALLRADIUS + 5*BASE)
- #define NEARPOCKET (9*BASE)
- #define SCRNPOCKET (POCKET / BASE)
- #define CUETIP 10
- #define MAXCUELENGTH 80
-
- #define CLOCKWISE 1
- #define ANTICLOCKWISE 2
- #define SMALL 1
- #define LARGE 2
- #define UP 1
- #define DOWN 2
- #define NOHIT -1
- #define ON TRUE
- #define OFF FALSE
- #define HIT 3
- #define UPDATE 3
- #define ICON 2
-
- #define FRICTION (BASESP / 500)
- #define SPINFRICTION 3
- #define SPEEDINC (BASESP / 16)
- #define MAXSPEED (BASESP * 4)
-
- #define DEFAULT 30000
-
- #define RACKED 1
- #define BROKEN 0
- #define OPEN 2
-
- #define PRACTICE 2
-
- #define CLEARJAWS 0
- #define BALLINJAWS 1
- #define AVOIDJAWS 2
-
- void ChangePower();
- void ChangeSpin(void);
- void DrawCross(short);
- void MoveCue(short,short);
- short FindAngle(WORD,WORD,WORD);
- short TouchingBall(short);
- void PlayComputerShot(void);
- void CopyBalls(struct ballstruct *,struct ballstruct *);
- WORD QuickRoot(long);
- void CheckAngle(short *);
- short NearPocket(short);
- short CheckPocket(short);
- UWORD Rand(UWORD);
-
- enum msg { MSG_PLACECUEBALL,MSG_FOUL,MSG_WINS,MSG_MICHAEL,MSG_JOSH,
- MSG_CLAIRE,MSG_SALLY,MSG_PLAYER1,MSG_PLAYER2,MSG_QUITTING,
- MSG_VS,MSG_GAME,MSG_OF,MSG_0,MSG_1,MSG_2,MSG_3,MSG_4,MSG_5,
- MSG_GOODSHOT,MSG_SHOTCANCELLED,MSG_BADLUCK,MSG_WELLDONE,
- MSG_QUITGAME,MSG_ISTHECHAMP,MSG_OOOPS };
-
- enum balltype { white,black,yellow,red, anyball,baize };
- struct ballstruct
- {
- enum balltype colour;
- char potted,justpotted,hasmoved,lasthit,olddx,olddy;
- USHORT x,y;
- short speed,angle,scrnx,scrny,oldscrnx,oldscrny;
- };
- struct ballstruct ball[16],tempball[16];
-
- struct playerstruct
- {
- enum balltype colour;
- char goes,wins;
- char nametag;
- short maxpower;
- char cuepulls,skill;
- };
- struct playerstruct player[8];
-
- short *memblock, *quicksin, *quickcos, *quickarcsin;
-
- WORD cueangle,cuespeed,powerdirn,spinx,spiny;
-
- short gametype,cloth,firsthit,packstate,turn,foul,balls,
- endofgame,cheatangle,cheatball;
-
- USHORT pocketx[6] = { (TABLELENGTH-BALLRADIUS),(TABLELENGTH-BALLRADIUS),
- (TABLELENGTH/2),(TABLELENGTH/2),BALLRADIUS,BALLRADIUS };
-
- USHORT pockety[6] = { (TABLEWIDTH-BALLRADIUS),BALLRADIUS,
- (TABLEWIDTH-BALLRADIUS),BALLRADIUS,(TABLEWIDTH-BALLRADIUS),BALLRADIUS };
-
- char angleused[360];
-
- /**********************/
- short TouchingBall(col)
- short col;
- {
- register short i;
-
- for (i=0; i<balls; i++)
- {
- if (!ball[i].potted && i!=col)
- {
- register long dx = ball[col].x - ball[i].x;
-
- if (dx < BALLDIAMETER && dx > (-BALLDIAMETER))
- {
- register long dy = ball[col].y - ball[i].y;
- if (dy < BALLDIAMETER && dy > (-BALLDIAMETER))
- if (QuickRoot(dx*dx + dy*dy) < BALLDIAMETER)
- return(i);
- }
- }
- }
- return(NOHIT);
- }
- /************************/
- short NearPocket(i)
- short i;
- {
- char j;
-
- for (j=0; j<6; j++)
- if (abs(ball[i].x - pocketx[j]) < NEARPOCKET &&
- abs(ball[i].y - pockety[j]) < NEARPOCKET) return(TRUE);
- return(FALSE);
- }
- /************************/
- short CheckPocket(i)
- short i;
- {
- short j;
-
- for (j=1; j<balls; j++)
- {
- if (!ball[j].potted &&
- abs(ball[j].x - pocketx[i]) < NEARPOCKET &&
- abs(ball[j].y - pockety[i]) < NEARPOCKET) return(j);
- }
- return(FALSE);
- }
- /************************/
- void PlayComputerShot()
- {
- short i,j,k,l,limit,opp,adj,dx,dy,angle,hitball,
- hypcue,anglecol,hypcol,anglecue,relangle,
- potspeed=DEFAULT,hitspeed=DEFAULT,speed,
- potangle,hitangle,potbackspin,nearpocket,
- jaws,forgetcolour=FALSE;
-
- long x,y;
-
- CopyBalls(ball,tempball);
-
- /* CPU can forget its ball colour! */
- if (player[turn].skill==0 && player[turn].colour!=black && !(Rand(10)))
- forgetcolour=TRUE;
-
- for(i=1; i<balls; i++)
- if ((ball[i].colour==player[turn].colour ||
- (forgetcolour && ball[i].colour!=black) ||
- (ball[i].colour!=black && player[turn].colour==anyball) ||
- gametype==PRACTICE) && !ball[i].potted)
- {
- for (j=0; j < (6+1); j++)
- {
- if (j==6)
- {
- opp = (ball[i].x - ball[CUE].x) / BASEII;
- adj = (ball[i].y - ball[CUE].y) / BASEII;
- hypcue = QuickRoot(opp*opp + adj*adj);
- anglecue = FindAngle(opp,adj,hypcue);
- anglecol = anglecue; hypcol = hypcue;
- relangle = 0;
- }
- else
- {
- opp = (pocketx[j] - ball[i].x) / BASEII;
- adj = (pockety[j] - ball[i].y) / BASEII;
- hypcol = QuickRoot(opp*opp + adj*adj);
- anglecol = FindAngle(opp,adj,hypcol);
-
- x = ball[i].x - SCRNBALLDIAMETER * quicksin[anglecol];
- y = ball[i].y - SCRNBALLDIAMETER * quickcos[anglecol];
- opp = (x - ball[CUE].x) / BASEII;
- adj = (y - ball[CUE].y) / BASEII;
- hypcue = QuickRoot(opp*opp + adj*adj);
- anglecue = FindAngle(opp,adj,hypcue);
- relangle = abs(anglecol-anglecue);
- if (relangle > 180) relangle=360-relangle;
- }
- if (relangle < 70)
- {
- dx = quicksin[anglecue]<<1;
- dy = quickcos[anglecue]<<1;
- limit = hypcue / ((BASE<<1)/BASEII) + 10;
-
- for (k=0; k<limit; k++)
- {
- hitball=TouchingBall(CUE);
- if (hitball!=NOHIT) break;
- ball[CUE].x+=dx; ball[CUE].y+=dy;
- }
- nearpocket = NearPocket(CUE);
-
- ball[CUE].x = tempball[CUE].x;
- ball[CUE].y = tempball[CUE].y;
-
- if (hitball!=NOHIT && hitball!=i && !nearpocket &&
- (ball[hitball].colour==player[turn].colour ||
- (player[turn].colour==anyball &&
- ball[hitball].colour!=black)))
- {
- speed = hypcue * (BASEII*MAXSPEED/BASE) / 600;
-
- if (speed < hitspeed)
- { hitspeed = speed; hitangle = anglecue; }
- }
- else if (hitball==i && !nearpocket)
- {
- /* Cue ball path is clear */
-
- dx = quicksin[anglecol] << 1;
- dy = quickcos[anglecol] << 1;
-
- do
- {
- ball[i].x += dx; ball[i].y += dy;
- hitball = TouchingBall(i);
- if (ball[i].x < BALLRADIUS ||
- ball[i].x > (TABLELENGTH-BALLRADIUS) ||
- ball[i].y < BALLRADIUS ||
- ball[i].y > (TABLEWIDTH-BALLRADIUS)) break;
-
- } while (hitball==NOHIT);
-
- ball[i].x = tempball[i].x;
- ball[i].y = tempball[i].y;
-
- if (hitball==NOHIT && j!=6) /* We've found a pot! */
- {
- speed = (hypcol+hypcue) * (BASEII*MAXSPEED/BASE)
- / ((100-relangle)*4)
- * (hypcol+(TABLELENGTH/BASEII))
- / (hypcue+(TABLELENGTH/BASEII));
-
- if (speed < potspeed)
- {
- potspeed = speed; potangle = anglecue;
- /* check for in/off situ */
- if (relangle < 5 || NearPocket(i))
- potbackspin = TRUE;
- else potbackspin = FALSE;
- if (player[turn].nametag==MSG_JOSH ||
- player[turn].nametag==MSG_PLAYER1 ||
- player[turn].nametag==MSG_PLAYER2)
- { cheatangle = anglecol; cheatball = i; }
- }
- }
- else if (potspeed==DEFAULT)
- {
- /* Can hit but not pot */
-
- if (hitball!=NOHIT && NearPocket(hitball))
- {
- if (ball[hitball].colour==
- player[turn].colour ||
- (player[turn].colour==anyball &&
- ball[hitball].colour!=black))
- jaws = BALLINJAWS;
- else jaws = AVOIDJAWS;
- }
- else jaws = CLEARJAWS;
-
- speed = hypcue * (BASEII*MAXSPEED/BASE)
- / ((100-relangle)*3);
- if (jaws==BALLINJAWS) speed<<=2;
-
- if (speed < hitspeed && jaws!=AVOIDJAWS)
- {
- hitspeed = speed;
- hitangle = anglecue;
- }
- }
- }
- }
- }
- }
-
- if (hitspeed==DEFAULT && potspeed==DEFAULT) /* Snooker situation */
- {
- for(i=1; i<balls; i++)
- if ((ball[i].colour==player[turn].colour ||
- (ball[i].colour!=black && player[turn].colour==anyball) ||
- gametype==PRACTICE) && !ball[i].potted)
- {
- for (j=0; j<4; j++) for (l=0; l<5; l++)
- {
- short xdisp,ydisp;
- long dx,dy;
-
- switch(l)
- {
- case 0: xdisp = 0; ydisp = 0; break;
-
- case 1: xdisp = (-BALLRADIUS);
- ydisp = (-BALLRADIUS); break;
-
- case 2: xdisp = BALLRADIUS;
- ydisp = (-BALLRADIUS); break;
-
- case 3: xdisp = (-BALLRADIUS);
- ydisp = BALLRADIUS; break;
-
- case 4: xdisp = BALLRADIUS;
- ydisp = BALLRADIUS; break;
- }
-
- dx = ball[i].x+xdisp - ball[CUE].x;
- dy = ball[i].y+ydisp - ball[CUE].y;
-
- switch(j)
- {
- case 0: y = ball[CUE].y +
- dy * ball[CUE].x /
- (ball[i].x+xdisp + ball[CUE].x);
- x = BALLRADIUS; break;
-
- case 1: y = ball[CUE].y +
- dy * (TABLELENGTH - ball[CUE].x) /
- ((TABLELENGTH - (ball[i].x+xdisp)) +
- (TABLELENGTH - ball[CUE].x));
- x = TABLELENGTH - BALLRADIUS; break;
-
- case 2: x = ball[CUE].x +
- dx * ball[CUE].y /
- (ball[i].y+ydisp + ball[CUE].y);
- y = BALLRADIUS; break;
-
- case 3: x = ball[CUE].x +
- dx * (TABLEWIDTH - ball[CUE].y) /
- ((TABLEWIDTH - (ball[i].y+ydisp)) +
- (TABLEWIDTH - ball[CUE].y));
- y = TABLEWIDTH - BALLRADIUS; break;
- }
- opp = (x - ball[CUE].x) / BASEII;
- adj = (y - ball[CUE].y) / BASEII;
- hypcue = QuickRoot(opp*opp + adj*adj);
- anglecue = FindAngle(opp,adj,hypcue);
-
- opp = (x - (ball[i].x+xdisp)) / BASEII;
- adj = (y - (ball[i].y+ydisp)) / BASEII;
- hypcol = QuickRoot(opp*opp + adj*adj);
-
- dx = quicksin[anglecue] << 1;
- dy = quickcos[anglecue] << 1;
-
- do
- {
- ball[CUE].x += dx; ball[CUE].y += dy;
- if (ball[CUE].x < BALLRADIUS ||
- ball[CUE].x > (TABLELENGTH-BALLRADIUS) ||
- ball[CUE].y < BALLRADIUS ||
- ball[CUE].y > (TABLEWIDTH-BALLRADIUS)) break;
-
- hitball = TouchingBall(CUE);
-
- } while (hitball==NOHIT);
-
- if (hitball==NOHIT && !(NearPocket(CUE)))
- {
- /* Path to cushion is clear */
- if (j <= 1) dx = -dx; else dy = -dy;
-
- limit = (hypcol / ((BASE<<1)/BASEII)) + 10;
-
- for (k=0; k<limit; k++)
- {
- hitball=TouchingBall(CUE);
- if (hitball!=NOHIT) break;
- ball[CUE].x += dx; ball[CUE].y += dy;
- }
-
- if (hitball==i)
- {
- /* Found a path off a cushion! */
- speed = (hypcue+hypcol) *
- (BASEII*MAXSPEED/BASE) / 300;
- if (speed < hitspeed)
- {
- hitspeed = speed;
- hitangle = anglecue;
- ball[CUE].x = tempball[CUE].x;
- ball[CUE].y = tempball[CUE].y;
- break;
- }
- }
- }
- ball[CUE].x = tempball[CUE].x;
- ball[CUE].y = tempball[CUE].y;
- }
- }
- }
-
- spiny = (Rand(1200)+Rand(1200))/2 - 800;
-
- if (potspeed != DEFAULT)
- {
- ball[CUE].speed = potspeed + Rand((UWORD)(potspeed>>1));
- ball[CUE].angle = potangle;
- if (potbackspin) /* could be an "in/off" situ */
- spiny = (Rand(800)+Rand(800))/2 - 800;
- }
- else if (hitspeed != DEFAULT)
- {
- ball[CUE].speed = hitspeed + Rand(MAXSPEED);
- ball[CUE].angle = hitangle;
- }
- else /* Ooops! We're fully snookered! */
- {
- short lasthope=FALSE;
-
- /* Try to illegally knock in any of our balls over pockets */
- for (i=0; i<6; i++)
- {
- if ((j = CheckPocket(i)) &&
- ball[j].colour==player[turn].colour &&
- (player[turn].colour!=black ||
- (player[turn].colour==anyball &&
- ball[j].colour!=black)))
- {
- opp = (pocketx[i] - ball[CUE].x) / BASEII;
- adj = (pockety[i] - ball[CUE].y) / BASEII;
- hypcue = QuickRoot(opp*opp + adj*adj);
- ball[CUE].angle = FindAngle(opp,adj,hypcue);
- ball[CUE].speed = player[turn].maxpower;
- spiny = (Rand(800)+Rand(800))/2 - 800;
- lasthope = TRUE; break;
- }
- }
- if (!lasthope)
- {
- ball[CUE].angle = Rand(360);
- ball[CUE].speed = player[turn].maxpower;
- /* little anim! */
- j = 36 + Rand(49);
- for (i=0; i<j; i++) MoveCue(CLOCKWISE,LARGE);
- }
- }
- if (packstate==RACKED) ball[CUE].speed = player[turn].maxpower;
-
- /* Add player characteristics */
- angle = ((Rand(8)-4) * (3-player[turn].skill))/3;
- if (player[turn].colour==black) angle*=2;
- ball[CUE].angle+=angle;
- CheckAngle(&ball[CUE].angle);
-
- ball[CUE].speed = ball[CUE].speed * player[turn].maxpower / MAXSPEED;
- if (ball[CUE].speed > player[turn].maxpower)
- ball[CUE].speed = player[turn].maxpower;
- if (ball[CUE].speed < BASESP) ball[CUE].speed=BASESP;
- if (ball[CUE].speed > MAXSPEED) ball[CUE].speed=MAXSPEED;
-
- angle = ball[CUE].angle+180;
- CheckAngle(&angle);
-
- i=LARGE; j=0;
- while(cueangle!=angle)
- {
- if ((angle-cueangle<180 && angle-cueangle>=0) ||
- angle-cueangle<-180)
- {
- if (j==2) i=SMALL;
- j=1; MoveCue(CLOCKWISE,i);
- }
- else
- {
- if (j==1) i=SMALL;
- j=2; MoveCue(ANTICLOCKWISE,i);
- }
- }
-
- while(cuespeed < ball[CUE].speed) { ChangePower(); WaitTOF(); }
- PlayShot();
- }
-